import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Integrator implements Runnable {
  Environment env;
  
  Integrator(Environment env) {this.env = env;}
  
  void run() {
    while (env.time.current[0] < env.stopTime) {
      env.integrate(env.archive.dt);
    }
    env.saveArchive();
  }
}



void runBeringEnsemble(String copepodName, String forcingFile, float startTime, float stopTime, String outputBasename, int stride, String paramFile) {
  int nThreads = 7;
  
  int K = 15;
  float H0 = 150;
  float dz0 = 5;
  
  String basePath = "/Users/neil/Dropbox/bering/";
  forcingFile = basePath + forcingFile;
  paramFile = basePath + paramFile;
  
  print("reading forcing...");
  ForcingSet forcing = new ForcingSet(forcingFile);
  println("done (" + forcing.length() + " cases, " + forcing.time().length + " times)");
  
  int c = 0;
  while (c < forcing.length()) {
    // create a new batch of cs, assign each to an integrator, run them, wait till all are done
    Environment env = null;
    ExecutorService pool = Executors.newFixedThreadPool(nThreads);
    for (int i=0; i<nThreads & c < forcing.length(); i++) {
      env = new BeringWaterCol(K, H0, dz0, paramFile, copepodName, startTime, stopTime, forcing, c);
      env.shortname = outputBasename + "_" + c;
      env.wakeup();
      env.archive.filename = basePath + outputBasename + "_" + c;
      
      if (i==0) print("starting ");
      print(c + "...");
      pool.submit(new Integrator(env));
      c += stride;
    }
    pool.shutdown();
    float tic = millis();
    while (!pool.isTerminated()) {
      if (millis()-tic > 5000) {
        println("    " + env.time.current[0]);
        tic = millis();
      }
    }
    println("done");
  }
}



void runBeringTuningEnsemble(String copepodName, String forcingFile, float startTime, float stopTime, String outputBasename, String paramFile, int NC) {
  int nThreads = 7;
  
  int K = 15;
  float H0 = 150;
  float dz0 = 5;
  
  String basePath = "/Users/neil/Dropbox/bering/";
  forcingFile = basePath + forcingFile;
  paramFile = basePath + paramFile;
  
  print("reading forcing");
  ForcingSet forcing = new ForcingSet(forcingFile);
  
  for (int c=0; c<NC; c+=nThreads) {
    // create a new batch of cases, assign each to an integrator, run them, wait till all are done
    Environment env = null;
    ExecutorService pool = Executors.newFixedThreadPool(nThreads);
    for (int i=0; i<nThreads; i++) {
      env = new BeringWaterCol(K, H0, dz0, paramFile, copepodName, startTime, stopTime, forcing, 0);

      env.getParam("mu0_SP").initial = random(0.4,0.8);
      env.getParam("PARcomp").initial = random(0,10);
      env.getParam("m_SP").initial = random(0,0.2);
      env.getParam("m_LP").initial = random(0,0.2);
      env.getParam("m_MZ").initial = random(0.5,2);
      env.getParam("phi_MZ_SP").initial = random(0.5,1);
      env.getParam("wsink_SD").initial = pow(10,random(0,1));
      float ic_P = 2*pow(10,random(-2,-1));
      float ic_LPfrac = random(0.1,0.5);
      env.getParam("ic_SP").initial = (1-ic_LPfrac) * ic_P; // these aren't actually applied to the initial conditions, which are set in the constructor!
      env.getParam("ic_LP").initial = ic_LPfrac * ic_P;
      
      env.shortname = outputBasename + "_" + (c+i);
      env.wakeup();
      env.archive.filename = basePath + outputBasename + "_" + (c+i);
      
      if (i==0) print("starting ");
      print("" + (c+i) + "...");
      pool.submit(new Integrator(env));
    }
    pool.shutdown();
    float tic = millis();
    while (!pool.isTerminated()) {}
    println("done");
  }
}
